﻿using Furion;
using GMS.NET.Const;
using GMS.NET.Core.Options;
using GMS.NET.Core.Provider.CacheProvider;
using GMS.NET.Core.Users;
using SqlSugar;

namespace GMS.NET.SqlSugarCore.DbCore
{
    public class DbManger
    {
        /// <summary>
        /// 自动获取业务库对象 （用IOC这块代码不能写到IOC里面）
        /// </summary>
        public static ISqlSugarClient BizDb
        {
            get
            {
                var User = GetUserInfo();//集团ID（也可以叫租户ID）
                if (!Db.IsAnyConnection(User.CusId))
                {
                    //用非默认ConfigId进行测试
                    //添加业务库只在当前上下文有效（原理：SqlSugarScope模式入门文档去看）
                    Db.AddConnection(new ConnectionConfig()
                    {
                        ConfigId = User.CusId,
                        ConnectionString = User.Connection,
                        DbType = DbType.SqlServer,
                        IsAutoCloseConnection = true
                    });
                }
                //原理说明
                //IsAnyConnection、AddConnection和GetConnection 都是Scope周期不同请求不会有影响

                var result = Db.GetConnection(User.CusId);

                //可以给业务库result设置AOP和过滤滤器

                return result;
            }
        }
        /// <summary>
        /// 手动获取业务库对象 （用IOC这块代码不能写到IOC里面）
        /// 一般是管理员使用 未使用缓存处理 直接访问数据库
        /// </summary>
        /// <returns></returns>
        public static ISqlSugarClient GetBizDb(Guid TenantId)
        {
            var ConnectionId = TenantId.ToString();
            //如果使用频繁 可在此处添加二级缓存
            var Connection = MasterDb.Queryable<GMSNet_Customer>()
                .Where(x => x.Id == TenantId)
                .Select(x => x.Cust_Connection).First();

            if (!Db.IsAnyConnection(ConnectionId))
            {
                //用非默认ConfigId进行测试
                //添加业务库只在当前上下文有效（原理：SqlSugarScope模式入门文档去看）
                Db.AddConnection(new ConnectionConfig()
                {
                    ConfigId = ConnectionId,
                    ConnectionString = Connection,
                    DbType = DbType.SqlServer,
                    IsAutoCloseConnection = true
                });
            }
            //原理说明
            //IsAnyConnection、AddConnection和GetConnection 都是Scope周期不同请求不会有影响

            var result = Db.GetConnection(ConnectionId);

            //可以给业务库result设置AOP和过滤滤器

            return result;
        }
        /// <summary>
        /// 获取租户客户端
        /// </summary>
        /// <param name="Connection"></param>
        /// <param name="ConfigId"></param>
        /// <returns></returns>
        public static ISqlSugarClient BizDbInitialize(string Connection, string ConfigId)
        {
            if (!Db.IsAnyConnection(ConfigId))
            {
                Db.AddConnection(new ConnectionConfig()
                {
                    ConfigId = ConfigId,
                    ConnectionString = Connection,
                    DbType = DbType.SqlServer,
                    IsAutoCloseConnection = true,
                    AopEvents = new AopEvents()
                    {
                        //OnLogExecuting = (sql, args) =>
                        //{

                        //}
                    }
                });
            }

            var result = Db.GetConnection(ConfigId);

            return result;
        }
        /// <summary>
        /// 请在大数据集合丶分表丶主键为Id类型为Guid新增或修改时使用
        /// 请勿在缺少该些条件时使用
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="client">执行数据操作的客户端</param>
        /// <param name="dataSet">执行的数据集合</param>
        /// <param name="dbOperation">数据集合的操作类型</param>
        /// <param name="updateColumns">如果是修改可设置修改特定字段对大数据集合修改有益(选填)</param>
        /// <returns>执行成功的数量</returns>
        public static int SetSplitDsInsertOrUpdate<T>(ISqlSugarClient client, List<T> dataSet, DbOperation dbOperation, string[] updateColumns = null) where T : class, new()
        {
            if (dbOperation == DbOperation.Insert)
            {
                if (dataSet.Any())
                {
                    if (dataSet.Count() > 10000)
                        return client.Fastest<T>().SplitTable().BulkCopy(dataSet.SetGuid());
                    else
                        return client.Insertable(dataSet).SplitTable().ExecuteCommand();
                }
            }
            if (dbOperation == DbOperation.Update)
            {
                if (dataSet.Any())
                {
                    if (dataSet.Count() > 10000)
                        return client.Fastest<T>().SplitTable().BulkUpdate(dataSet);
                    else
                    {
                        var isUpdateCols = updateColumns is not null && updateColumns.Length > 0;
                        if (isUpdateCols)
                            return client.Updateable(dataSet).UpdateColumns(updateColumns).SplitTable(x => x.GetRange()).ExecuteCommand();
                        else
                            return client.Updateable(dataSet).SplitTable(x => x.GetRange()).ExecuteCommand();
                    }
                }
            }
            return 0;
        }
        /// <summary>
        /// 获基础信息库对象 （用IOC这块代码不能写到IOC里面）
        /// </summary>
        public static ISqlSugarClient MasterDb
        {
            get
            {
                //如果是跨服务器分库，也需要动态配置的，因为库的IP会变
                //参考业务库用法
                return Db.GetConnection(App.GetOptions<ConnectionStringsOptions>().ConfigId);
            }
        }
        /// <summary>
        /// 通过IOC获取注入的Db对象
        /// </summary>
        public static SqlSugarScope Db => (SqlSugarScope)App.GetService<ISqlSugarClient>();
        /// <summary>
        /// 注入缓存
        /// </summary>
        private readonly static ICachingService cache = App.GetService<ICachingProvider>().GetCache();
        /// <summary>
        /// 获取用户数据库连接字符串信息
        /// </summary>
        /// <returns></returns>
        private static SaasUserInfo GetUserInfo()
        {
            //读数据库配置一般会有缓存，不然浪费性能
            return cache.GetAsync<SaasUserInfo>(UserClaimConst.CacheConnectString(UserInfo.UserId)).Result;
        }
    }
    public enum DbOperation
    {
        Insert,
        Update
    }
}